﻿using System.Reflection;
using DatabaseProxy.Attributes;

namespace DatabaseProxy.ObjectSql;

public class ObjectSqlInserter<T> where T : IDatabaseTable
{
    private static string _sql = "";
    private static Dictionary<int, string> _dictionarySqlCount = new();
    public static string Sql {
        get {
            if (!string.IsNullOrEmpty(_sql)) 
            {
                return _sql;
            }
            else {
                Queue<string> sql_queue = new();
                sql_queue.Enqueue("INSERT INTO ");
                var type = typeof(T);
                string tableName = type.Name;
                if (type.IsDefined(typeof(TableNameAttribute), false)) {
                    var tableNameAttribute = type.GetCustomAttribute(typeof(TableNameAttribute), false) as TableNameAttribute;
                    tableName = tableNameAttribute?.Name ?? tableName;
                }
                sql_queue.Enqueue(tableName);
                sql_queue.Enqueue("(");
                Queue<string> column_queue = new();
                Queue<string> value_queue = new();
                foreach (var propertyInfo in type.GetProperties()) {
                    if (propertyInfo.IsDefined(typeof(IdentityAttribute), false)) continue;
                    string columnName = propertyInfo.Name;
                    if (propertyInfo.IsDefined(typeof(ColumnNameAttribute), false)) {
                        var attribute = propertyInfo.GetCustomAttribute(typeof(ColumnNameAttribute), false) as ColumnNameAttribute;
                        columnName = attribute?.Name ?? columnName;
                    }
                    column_queue.Enqueue(columnName);
                    value_queue.Enqueue($"@{propertyInfo.Name}");
                }
                sql_queue.Enqueue(string.Join(",", column_queue));
                sql_queue.Enqueue(")");
                sql_queue.Enqueue("VALUES(");
                sql_queue.Enqueue(string.Join(",", value_queue));
                sql_queue.Enqueue(")");

                return string.Join("  ", sql_queue);
            }
        }
    }

    public static string MultipleSql(int count)
    {
        if (!_dictionarySqlCount.Keys.Contains(count))
        {
            Queue<string> sql_queue = new();
            sql_queue.Enqueue("INSERT INTO ");
            var type = typeof(T);
            string tableName = type.Name;
            if (type.IsDefined(typeof(TableNameAttribute), false)) {
                var tableNameAttribute = type.GetCustomAttribute(typeof(TableNameAttribute), false) as TableNameAttribute;
                tableName = tableNameAttribute?.Name ?? tableName;
            }
            sql_queue.Enqueue(tableName);
            sql_queue.Enqueue("(");
            Queue<string> column_queue = new();
            Queue<string> value_queue = new();
            foreach (var propertyInfo in type.GetProperties()) {
                if (propertyInfo.IsDefined(typeof(IdentityAttribute), false)) continue;
                string columnName = propertyInfo.Name;
                if (propertyInfo.IsDefined(typeof(ColumnNameAttribute), false)) {
                    var attribute = propertyInfo.GetCustomAttribute(typeof(ColumnNameAttribute), false) as ColumnNameAttribute;
                    columnName = attribute?.Name ?? columnName;
                }
                column_queue.Enqueue(columnName);
                value_queue.Enqueue($"@{propertyInfo.Name}");
            }
            sql_queue.Enqueue(string.Join(",", column_queue));
            sql_queue.Enqueue(")");
            sql_queue.Enqueue("VALUES");
            for (int i = 0; i < count; i++)
            {
                sql_queue.Enqueue("(");
                sql_queue.Enqueue(string.Join(",", value_queue.Select(l => l + i).ToArray()));
                sql_queue.Enqueue(")");
                if (i < count - 1)
                {
                    sql_queue.Enqueue(",");
                }
            }
            _dictionarySqlCount.Add(count, string.Join(" ", sql_queue));
        }
        return _dictionarySqlCount[count];
    }
}